#pragma once
#include<iostream>
#include<pthread.h>
#include<stdio.h>
#include<queue>

using namespace std;
const int gmaxcap=5;
template<class T>
class blockqueue
{
public:
blockqueue(const int maxcap=gmaxcap)
:_maxcap(maxcap)
{
    pthread_mutex_init(&_mut,nullptr);//互斥量的初始化
    pthread_cond_init(&_pcond,nullptr);//供应商的条件变量初始化
    pthread_cond_init(&_ccond,nullptr);//消费者的条件变量初始化
}

void push(const T &in)//输入型参数，用&
{
pthread_mutex_lock(&_mut);//加锁

while(is_full())//供应商应该判断阻塞队列中是否满了，若满了需要阻塞等待队列中有空余的位置再push in
{
    //满了进函数体
    pthread_cond_wait(&_pcond,&_mut);
//阻塞。这个函数调用，会使调用函数的线程自动解锁，然后阻塞在队列中，等到被唤醒时自动加锁
}
//走到这里说明阻塞队列中有余位可以提供
_q.push(in);//push数据进阻塞队列
pthread_mutex_unlock(&_mut);//解锁
pthread_cond_signal(&_ccond);//唤醒消费者
}

void pop(T* out)//输出型参数，用*，输入输出型参数，用&
{
pthread_mutex_lock(&_mut);//加锁
while(is_empty())//消费者判断队列是否为空，若没空可以在队列中取数据
{
    //队列为空进来
   pthread_cond_wait(&_ccond,&_mut);//阻塞等待供应商唤醒，唤醒时即队列不为空了
}
*out=_q.front();//把队列的头节点对象赋给输出型参数，实际上是调用拷贝构造构造一个无参的对象
_q.pop();
pthread_mutex_unlock(&_mut);//解锁
pthread_cond_signal(&_pcond);//唤醒供应商，此时消费者已经在队列中取一个数据了，说明此时队列中至少有一个空位，那么供应商可以往队列中push了
}
~blockqueue()
{
    pthread_mutex_destroy(&_mut);//互斥量的销毁
    pthread_cond_destroy(&_pcond);//供应商的条件变量销毁
    pthread_cond_destroy(&_ccond);//消费者的条件变量销毁
}
bool is_full()
{
    return _q.size()==_maxcap;//判断此时阻塞队列的个数是否满了
}

bool is_empty()
{
    return _q.empty();//判断阻塞队列是否为空
}

    private:
  queue<T> _q;//阻塞队列
  int _maxcap;//队列中的最大个数
  pthread_mutex_t _mut;//一个锁
  pthread_cond_t _pcond;//供应商的条件变量
  pthread_cond_t _ccond;//消费者的条件变量

};

